%% Author: zyb
%% Created: 2008-12-22
%% Description: TODO: Add description to metaDB

-module(ifriend_db).
-import(lists, [foreach/2]).
%%
%% Include files
%%
-include("../include/header.hrl").
-include_lib("stdlib/include/qlc.hrl").
%%
%% Exported Functions
%%
%-export([]).
-compile(export_all).

%%
%% API Functions
%%

start_mnesia()->
    
    case mnesia:create_schema([node()]) of
        ok ->
            do_this_once();
        _ ->
            LOG = #metalog{logtime = calendar:local_time(),logfunc="start_mnesia with latest data",logarg=[]},
            mnesia:start(),
			mnesia:wait_for_tables([account,login,frame,metalog,history], 14000),            
            logF(LOG)
    end,    
    start_mnesia_ok.

do_this_once() ->
    mnesia:start(),     
    mnesia:create_table(
      					account, 	%table name 
                        [			
                         {attributes, record_info(fields, account)},%table content
                         {disc_copies,[node()]}                         
                        ]
                       ),
    %%TODO: index.
    mnesia:create_table(
      					login, [{attributes, record_info(fields, login)},
                                       {disc_copies,[node()]}
                                      ]),
	
    mnesia:create_table(
      					frame, [{attributes, record_info(fields,frame)},
                                      {disc_copies,[node()]}
                                     ]),
	
	mnesia:create_table(
      					reply, [{attributes, record_info(fields,reply)},
                                      {disc_copies,[node()]}
                                     ]),
	
	mnesia:create_table(
      					notification, [{attributes, record_info(fields,notification)},
                                      {disc_copies,[node()]}
                                     ]),
	
    
    mnesia:create_table(
      					metalog, [{attributes, record_info(fields,metalog)},
                                      {disc_copies,[node()]}
                                     ]),
    mnesia:create_table(
      					history, [{type,bag},
                                  {attributes, record_info(fields,history)},
                                      {disc_copies,[node()]}
                                     ]),

    LOG = #metalog{logtime = calendar:local_time(),logfunc="start_mnesia && db reset",logarg=[]},
    mnesia:wait_for_tables([account,login,frame,metalog,history], 14000),
    reset_tables(),
    logF(LOG).

%% Local Functions
%%

do(Q) ->
    F = fun() -> qlc:e(Q) end,
    {atomic, Val} = mnesia:transaction(F),
    Val.

%% -record(account,{id,username,phone,nickname,friendlist,followerlist,permission}).
%% -record(frame,{  id,phone,frame,replys  }).
%% -record(login,{id,phone,username,status,session}).
example_tables() ->
    [     
     {account,1,gnibre,13810496765,dabing,{13811111111,13811111112},{},[],[]},
	 {account,2,t,13811111111,somet,{13810496765},{},[],[]},
	 {account,3,t2,13811111112,somet2,{13810496765},{},[],[]}, 
 	 {frame,1,"I'm happy~,ifriend is \"\" good!",[]},
	 {frame,2,"I'm happyyyyyyyyyyyyyyy,",[]},
	 {login,1,13810496765,gnibre,ssss,123},
	 {login,2,13810496765,gnibre,ssss,123},	 
	 {login,3,13810496765,gnibre,ssss,123}
	].

clear_tables()->
    LOG = #metalog{logtime = calendar:local_time(),logfunc="cleart_tables/0",logarg=[]},
    logF(LOG),

    mnesia:clear_table(account),    
    mnesia:clear_table(login),
    mnesia:clear_table(frame).

reset_tables() ->
    LOG = #metalog{logtime = calendar:local_time(),logfunc="reset_tables/0",logarg=[]},
    logF(LOG),    
    mnesia:clear_table(account),    
    mnesia:clear_table(login),    
    mnesia:clear_table(frame),
    F = fun() ->
		foreach(fun mnesia:write/1, example_tables())
		end,
    mnesia:transaction(F).

%% write a record 
%% 
write_to_db(X)->
    LOG = #metalog{logtime = calendar:local_time(),logfunc="write_to_db/1",logarg=[X]},
    logF(LOG),    
    %io:format("inside write to db"),
    F = fun() ->
		mnesia:write(X)
	end,
    {atomic,Val}=mnesia:transaction(F),
    Val.

%% delete a record 
%%
delete_object_from_db(X)->
	LOG = #metalog{logtime = calendar:local_time(),logfunc="delete_object_from_db/1",logarg=[X]},
    logF(LOG),
    %io:format("inside delete from db"),
    F = fun() ->
                mnesia:delete_object(X)
        end,
    mnesia:transaction(F).

delete_from_db(X)->
    LOG = #metalog{logtime = calendar:local_time(),logfunc="delete_from_db/1",logarg=[X]},
    logF(LOG),
    %io:format("inside delete from db"),
    F = fun() ->
                mnesia:delete(X)
        end,
    mnesia:transaction(F).

%% powerfull log function
logF(X)->
    F = fun() ->
		mnesia:write(X)
	end,
mnesia:transaction(F).

%% =====================================================================================================
select_all_from_Table(T)->    
    do(qlc:q([
              X||X<-mnesia:table(T)
              ])).  %result [L]
%%[ {},{},{},{}  ]

select_followedlist_from_account(ID) ->
    do(qlc:q([
              X#account.followedlist||X<-mnesia:table(account),X#account.id =:= ID
              ])).	 %result [L]

select_all_from_frame_byid(ID)->
	do(qlc:q([
              X||X<-mnesia:table(frame),X#frame.id =:= ID
              ])).	 %result [L]	
	

select_from_frame_byid(ID)->
    do(qlc:q([
              {X#frame.frame,X#frame.fid}||X<-mnesia:table(frame),X#frame.id =:= ID
              ])).	 %result [L]	

select_from_reply_by_fid(Fid)->
	do(qlc:q([			  
			  {replies_without_fid,X#reply.local_time,X#reply.poster,X#reply.replyto,X#reply.content}||
			  	X<-mnesia:table(reply),
				X#reply.fid =:= Fid
			  ])).	 %result [ #replies_without_fid{},#replies_without_fid{}....   ]

select_from_login_byid(ID)->
	do(qlc:q([
		  X||X<-mnesia:table(login),X#login.id =:= ID
			 ])).		

select_from_account_byid(ID)->
	do(qlc:q([
		  X||X<-mnesia:table(account),X#account.id =:= ID
			 ])).


%%===========================================================================================================
back_up_old_frame(ID)->
	{Frame,Fid} = select_from_frame_byid(ID),
	ListReply = select_from_reply_by_fid(Fid),
	ToWrite=#history{fid=Fid,local_time=erlang:localtime(),frame=Frame,list_replies_without_fid=ListReply},
		
	case write_to_db(ToWrite) of	
		ok->
			ok;
		Any->
			error_logger:error_msg("Write to db Res:_~p",[Any]),
			{error,Any}
	end.



%%Type 1  [%poster,%title]   ”%Usr 发表了新留言 %FOM ... "  发送给所有Follower
%%Type 3 [%poster, %title,%c]  "%C	在 %FOM 回复你:%C" 		->发送gei B
%%Type 5 "你的状态有了新回复"-> fom.id.

add_notification(ID,Type,Poster,Title,Content,Fomid)->
	case is_list(ID) of 
		false->			
			NewNotification = #notification{id = ID,local_time = erlang:localtime(),poster = Poster,type = Type,content = Content,link = Fomid,fresh = 1},
			F = fun() ->
						mnesia:write(NewNotification)
				end,	
			{atomic,Val}=mnesia:transaction(F),
			case Val of
				ok->
					ok;
				Why->
					{error,Why}
			end;
		true->
				WriteID = fun(SingleID)->
								  NewNo = #notification{id = SingleID,local_time = erlang:localtime(),poster = Poster,type = Type,content = Content,link = Fomid,fresh = 1},
								  mnesia:write(NewNo)
						  end,	
				F2= fun() ->
							foreach(WriteID, ID)
					end,
			
			{atomic,Val}=mnesia:transaction(F2),
			case Val of
				ok->
					ok;
				Why->
					{error,Why}
				end
	end.

	

make_notification(ID)->
		ok.		

				









































































  


%%------------------------------------------------------------------------------------------
%% select function
%% all kinds 
%%------------------------------------------------------------------------------------------ 


select_all_from_filemeta_byID(FileID) ->    %result [L]
    do(qlc:q([
              X||X<-mnesia:table(filemeta),X#filemeta.id =:= FileID
              ])).


select_hosts_from_chunkmapping_id(ChunkID) ->    
    do(qlc:q([X#chunkmapping.chunklocations||X<-mnesia:table(chunkmapping),X#chunkmapping.chunkid =:= ChunkID])).

select_filesize_from_filemeta(FileId) ->
	LOG = #metalog{logtime = calendar:local_time(),logfunc="select_filesize_from_filemeta/1",logarg=[FileId]},
    logF(LOG),    
    do(qlc:q([X#filemeta.size || X <- mnesia:table(filemeta),
                                   X#filemeta.id =:= FileId                                   
                                   ])).   %result [L]

% detach_from_chunk_mapping
% arg, Host name
%%TODO, 
detach_from_chunk_mapping(Host) ->
    DelHost =
        fun(ChunkMapping, Acc) ->
                ChunkLoc = ChunkMapping#chunkmapping.chunklocations,
                %%TODO, rewrite these,
                Guard = lists:member(Host,ChunkLoc),
                if Guard =:= true ->
                       ChunkLocList = ChunkLoc -- [Host],
                       case ChunkLocList of
                           []->
                               %delete chunkid record
                               ok = mnesia:delete(ChunkMapping);
                           _Any->
                               ok = mnesia:write(ChunkMapping#chunkmapping{chunklocations = ChunkLocList})
                       end
                end,
                Acc 
        end,
    DoDel = fun() -> mnesia:foldl(DelHost, [], chunkmapping, write) end,
    mnesia:transaction(DoDel).




append_a_file_record(FileRecord,ChunkMappingRecords) ->
    CurrentT = erlang:localtime(),
    [Old] = meta_db:select_all_from_filemeta_byID(FileRecord#filemeta.id),
    New = Old#filemeta{
                       mtime=CurrentT,
                       size = FileRecord#filemeta.size,
                       chunklist = Old#filemeta.chunklist++FileRecord#filemeta.chunklist
                      },
    F = fun() ->
		mnesia:write(New),
		lists:foreach(fun mnesia:write/1, ChunkMappingRecords)   
	end,
    {atomic, Val} = mnesia:transaction(F),
	Val.


            
